package com.luoling.attendance;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.luoling.readExcel.DbUtils;
import com.luoling.readExcel.ReadExcelV2;
import com.luoling.util.DateUtils;
import org.apache.ibatis.session.SqlSessionFactory;

import java.time.Duration;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Description:
 * Copyright:   Copyright (c)2024
 * Company:
 *
 * @author: 张李鑫
 * @version: 1.0
 * Create at:   2024-07-15 18:09:25
 * <p>
 * Modification History:
 * Date         Author      Version     Description
 * ------------------------------------------------------------------
 * 2024-07-15     张李鑫                     1.0         1.0 Version
 */
public class Attendance {


    public static void main(String[] args) throws Exception {
        checkList();
    }


    public static void checkList() throws Exception {
        SqlSessionFactory sqlSessionFactory = DbUtils.readMybatisConfig("mybatis-config.xml");
        CheckMapper mapper = sqlSessionFactory.openSession().getMapper(CheckMapper.class);
        List<Check> checks = mapper.list();
        Map<String, List<Check>> collect = checks.stream().collect(Collectors.groupingBy(Check::getName));
        ArrayList<Model> all = new ArrayList<>();
        collect.forEach((k, v) -> all.addAll(statistics1(filter(v))));
        HashMap<Integer, List<Model>> map = new HashMap<>();
        map.put(0, all);
        doWrite(map);
    }




    public static void doWrite(Map<Integer, List<Model>> writeTodo) {
        ExcelWriterBuilder write = EasyExcel.write(new Date().getTime() + "考勤.xlsx");
        try (ExcelWriter excelWriter = write.build()) {
            writeTodo.forEach((k, v) -> {
                WriteSheet sheet1 = EasyExcel.writerSheet(k, k.toString()).build();
                excelWriter.write(v, sheet1);
            });
        }
    }

    public static List<Check> filter(List<Check> checks) {
        Map<Date, List<Check>> collect = checks.stream()
                .collect(Collectors.groupingBy(Check::getDate,
                        Collectors.collectingAndThen(Collectors.toList(), list -> {
                            list.sort(Comparator.comparing(check -> LocalTime.parse(check.getTime())));
                            return list;
                        })));


        collect.forEach((k, v) -> {
            if (v.size() == 2) {
                Check check = v.get(0);
                Check check1 = v.get(1);
                Duration between = Duration.between(LocalTime.parse(check1.getTime()), LocalTime.parse(check.getTime()));
                if (Math.abs(between.toMinutes()) < 30) {
                    checks.remove(check1);
                }
            }
            if (v.size() > 2) {
                for (int i = 1; i < v.size() - 1; i++) {
                    checks.remove(v.get(i));
                }

            }
        });
        return checks;
    }

    public static ArrayList<Model> statistics1(List<Check> checks) {
        ArrayList<Model> result = new ArrayList<>();
        if (checks.isEmpty()) {
            return result;
        }
        Check firstCheck = checks.get(0);
        String dep = firstCheck.getDepartment();
        String name = firstCheck.getName();
        Date firstDate = firstCheck.getDate();

        if (checks.size() == 1) {
            result.add(oneCheckIn(dep, name, firstDate));
            return result;
        }
        checks.sort(Comparator.comparing(Check::getDate));

        int start = 0;

        for (int i = 1; i < checks.size(); i++) {
            Check check = checks.get(i);
            Date curDate = check.getDate();
            if (!curDate.equals(firstDate)) {
                Model model = i - start == 1 ?
                        oneCheckIn(dep, name, firstDate) :
                        buildModel(firstDate, firstCheck.getTime(), checks.get(i - 1).getTime(), dep, name);

                result.add(model);

                start = i;
                firstDate = curDate;
                firstCheck= checks.get(start);
            }
        }

        Model lastModel = start == checks.size() - 1 ?
                oneCheckIn(dep, name, firstDate) :
                buildModel(firstDate, firstCheck.getTime(), checks.get(checks.size() - 1).getTime(), dep, name);

        result.add(lastModel);
        return result;

    }


    public static ArrayList<Model> statistics(List<Check> checks) {
        checks.sort(Comparator.comparing(Check::getDate));
        ArrayList<Model> result = new ArrayList<>();
        Check firstCheck = checks.get(0);
        String dep = firstCheck.getDepartment();
        String name = firstCheck.getName();
        Date firstDate = firstCheck.getDate();

        int index = 0;
        int start = 0;
        int end = -1;
        while (index < checks.size()) {
            Check check = checks.get(index);
            Date curDate = check.getDate();
            if (!firstDate.equals(curDate)) {
                if (start == end) {
                    Model model = new Model(DateUtils.dateTime(checks.get(start).getDate()));
                    model.setHours(9);
                    model.setDepartment(dep);
                    model.setName(name);
                    result.add(model);
                } else {
                    result.add(buildModel(checks.get(start).getDate(), checks.get(start).getTime(), checks.get(end).getTime(), dep, name));
                }
                firstDate = curDate;
                start = index;
            } else {
                index++;
                end++;
            }

        }

        if (start >= end) {
            Model model = new Model(DateUtils.dateTime(checks.get(start).getDate()));
            model.setHours(9);
            model.setDepartment(dep);
            model.setName(name);
            result.add(model);
        } else {
            result.add(buildModel(checks.get(start).getDate(), checks.get(start).getTime(), checks.get(end).getTime(), dep, name));
        }
        return result;

    }

    public static Model oneCheckIn(String dep, String name, Date date) {
        Model model = new Model(DateUtils.dateTime(date));
        model.setHours(9);
        model.setDepartment(dep);
        model.setName(name);
        return model;
    }

    private static Model buildModel(Date date, String first, String next, String dep, String name) {
        LocalTime firstLocalTime = LocalTime.parse(first);
        LocalTime nextLocalTime = LocalTime.parse(next);

        Duration duration = Duration.between(firstLocalTime, nextLocalTime);

        return new Model(DateUtils.dateTime(date), Math.abs(duration.toMinutes()), dep, Math.abs(duration.toHours()), name);
    }


    public static class Model {
        @ExcelProperty("部门")
        @ColumnWidth(100)
        private String department;

        @ExcelProperty("姓名")
        @ColumnWidth(100)
        private String name;
        @ExcelProperty("日期")
        @ColumnWidth(100)
        private String date;
        @ExcelProperty("分钟")
        @ColumnWidth(100)
        private long minutes;

        @ExcelProperty("小时")
        @ColumnWidth(100)
        private long hours;

        public Model(String date) {
            this.date = date;
        }

        public Model(String date, long minutes, String department, long hours, String name) {
            this.date = date;
            this.minutes = minutes - hours * 60;
            this.department = department;
            this.hours = hours;
            this.name = name;
        }

        public long getMinutes() {
            return minutes;
        }

        public void setMinutes(long minutes) {
            this.minutes = minutes;
        }

        public String getDate() {
            return date;
        }

        public void setDate(String date) {
            this.date = date;
        }


        public long getHours() {
            return hours;
        }

        public void setHours(long hours) {
            this.hours = hours;
        }

        public String getDepartment() {
            return department;
        }

        public void setDepartment(String department) {
            this.department = department;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Model{" +
                    "department='" + department + '\'' +
                    ", name='" + name + '\'' +
                    ", date='" + date + '\'' +
                    ", minutes=" + minutes +
                    ", hours=" + hours +
                    '}';
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Model model = (Model) o;
            return minutes == model.minutes && hours == model.hours && Objects.equals(department, model.department) && Objects.equals(name, model.name) && Objects.equals(date, model.date);
        }

        @Override
        public int hashCode() {
            return Objects.hash(department, name, date, minutes, hours);
        }
    }



    public static void test(ArrayList<Model>all,ArrayList<Model>all1){
        HashMap<String, List<Model>> modelSet = new HashMap<>();
        HashMap<String, List<Model>> modelSet1 = new HashMap<>();
        HashSet<Model> set = new HashSet<>();
        HashSet<Model> set1 = new HashSet<>();


        set1.addAll(all1);
        set.addAll(all);


        for (Model model : set1) {
            if (!set.contains(model)){
                System.out.println("set  不包含model"+model.toString());
            }
        }

        for (Model model : set) {
            if (!set1.contains(model)){
                System.out.println("set 1 不包含model"+model.toString());
            }
        }

        for (Model model : all) {
            List<Model> array = modelSet.getOrDefault(model.getName(), new ArrayList<>());
            if (array.isEmpty()){
                modelSet.put(model.getName(),array);
            }
            array.add(model);

        }

        for (Model model : all1) {
            List<Model> array = modelSet1.getOrDefault(model.getName(), new ArrayList<>());
            if (array.isEmpty()){
                modelSet1.put(model.getName(),array);
            }
            array.add(model);
        }
        //Model{department='实施服务部', name='邱启元', date='2024-02-08', minutes=0, hours=9}


        System.out.println(123);
    }
}
